package com.ywm.service.impl;

import com.alibaba.fastjson.JSON;
import com.ywm.entity.Blog;
import com.ywm.service.BlogSrevice;
import com.ywm.service.ElasticSearchService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateRequestBuilder;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.reindex.UpdateByQueryAction;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.index.reindex.UpdateByQueryRequestBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class ElasticSearchServiceImpl implements ElasticSearchService {
    @Autowired
    private BlogSrevice blogSrevice;
    @Autowired
    private RestHighLevelClient client;
    BulkRequest request;
    //将MySQL中的数据放入es
    @Override
    public boolean getBlogAndToElasticSearch() {
        List<Blog> blogs = blogSrevice.list();
        //把查询的数据放入es
        request = new BulkRequest();
        request.timeout(TimeValue.timeValueSeconds(10));
        blogs.forEach(e -> {
            //添加数据
            request.add(
                    new IndexRequest("blogs")/*索引值不能大写开头*/
                            .source(JSON.toJSONString(e), XContentType.JSON).id(e.getBlogId())
            );
        });
        //上传
        try {
            BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
            //是否失败: bulk.hasFailures()
            return !bulk.hasFailures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    //新增时调用
    @Override
    public void saveOrUpdateToES(Blog blog) {
        request = new BulkRequest();
        request.timeout(TimeValue.timeValueSeconds(10));
        request.add(
                new IndexRequest("blogs")/*索引值不能大写开头*/
                        .source(JSON.toJSONString(blog), XContentType.JSON)
        );
        //上传
        try {
            BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
            //是否失败: bulk.hasFailures()
            bulk.hasFailures();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //根据内容查询博客
    @Override
    public List<Map<String, Object>> getBlogFromElasticSearch(String keyword, int pageNo, int pageSize) throws IOException {
        if (pageNo < 1) {
            pageNo = 0;
        }
        SearchRequest request = new SearchRequest("blogs");
        //构建器
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //多条件查询构造器
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //这里的must就是相当于我们mysql中的and关键字，如果你想用的是mysql中共的or关键字的话可以将must换成shoud。
        boolQueryBuilder.should(QueryBuilders.matchQuery("blogContent", keyword));
        boolQueryBuilder.should(QueryBuilders.matchQuery("blogTitle", keyword));
        builder.query(boolQueryBuilder);
        //设置超时时间
        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //分页
        builder.from(pageNo);
        builder.size(pageSize);
        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("blogContent");//在哪些字段里面筛选高亮
        highlightBuilder.field("blogTitle");//在哪些字段里面筛选高亮
        highlightBuilder.requireFieldMatch(false);//多个高亮显示
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        builder.highlighter(highlightBuilder);

        //执行搜索
        request.source(builder);
        SearchResponse search = client.search(request, RequestOptions.DEFAULT);
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {
            //解析高亮的字段
            Map<String, HighlightField> hf = hit.getHighlightFields();
            System.out.println(hf);
            HighlightField title1 = hf.get("blogTitle");
            HighlightField content = hf.get("blogContent");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
            if (title1 != null) {
                //将原来的字段替换替换为高亮的字段
                Text[] texts = title1.fragments();
                StringBuilder name = new StringBuilder();
                for (Text text : texts) {
                    name.append(text);
                }
                sourceAsMap.put("blogTitle", name.toString());
            }
            if (content != null) {
                //将原来的字段替换替换为高亮的字段
                Text[] texts = content.fragments();
                StringBuilder name = new StringBuilder();
                for (Text text : texts) {
                    name.append(text);
                }
                sourceAsMap.put("blogContent", name.toString());
            }
            list.add(hit.getSourceAsMap());
        }
        System.out.println(list);
        return list;
    }
    //更新
    @Override
    public void updateEs(Blog blog) {
        //获取文档对象
        UpdateRequest request = new UpdateRequest("blogs", blog.getBlogId());
        request.timeout(TimeValue.timeValueSeconds(2));
        request.doc(JSON.toJSONString(blog),XContentType.JSON);
        UpdateResponse update = null;
        try {
            update = client.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert update != null;
        System.out.println(update.status());
    }
    //删除
    @Override
    public void DeleteEs(String blogId) {
        //获取删除文档的对象
        DeleteRequest request = new DeleteRequest("blogs",blogId);
        request.timeout(TimeValue.timeValueSeconds(2));
        //执行删除操作
        DeleteResponse delete = null;
        try {
            delete = client.delete(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert delete != null;
        System.out.println(delete.status());
    }
}
